package com.nulldev.util.java.nFileBrowser.ui;

import javax.swing.AbstractAction;
import javax.swing.DefaultRowSorter;
import javax.swing.JComponent;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.Desktop;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.concurrent.ExecutionException;

import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.RowSorter;
import javax.swing.SortOrder;
import javax.swing.SwingWorker;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import com.nulldev.util.io.FileUtil;
import com.nulldev.util.io.MimeType;
import com.nulldev.util.java.nFileBrowser.BrowserView;
import com.nulldev.util.java.nFileBrowser.EntryTableModel;
import com.nulldev.util.java.nFileBrowser.ExceptionHandler;
import com.nulldev.util.java.nFileBrowser.FileBrowserException;
import com.nulldev.util.java.nFileBrowser.Localization;
import com.nulldev.util.java.nFileBrowser.entries.Entry;
import com.nulldev.util.java.nFileBrowser.entries.EntryFactory;
import com.nulldev.util.java.nFileBrowser.entries.FileSystemEntry;
import com.nulldev.util.java.nFileBrowser.preview.Preview;
import com.nulldev.util.java.nFileBrowser.preview.PreviewFactory;
import javax.swing.JLabel;
import java.awt.FlowLayout;
import javax.swing.BoxLayout;

public class SystemViewerView extends JPanel {
	private JTable table;
	
	private BrowserView view;
	
    private PreviewFactory previewFactory;
    
    private Entry currentEntry;

	/**
	 * Create the panel.
	 */
	public SystemViewerView() {
		setLayout(new BorderLayout(0, 0));
		
		JScrollPane scrollPane = new JScrollPane();
		add(scrollPane, BorderLayout.CENTER);
		
		table = new JTable() {
        	@Override
        	public void paintComponent(final Graphics g) {
        		final Graphics2D g2d = (Graphics2D) g;
        		g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        		super.paintComponent(g);
        	}
        };
        table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        table.setAutoCreateRowSorter(true);
        table.setShowVerticalLines(true);
        table.getTableHeader().setReorderingAllowed(false);
        
        EntryTableModel fileTableModel = new EntryTableModel(new ExceptionHandler() {
			
			@Override
			public void handleException(String message, Exception exception) {
				//exception.printStackTrace();
			}
		});
        Entry initialEntry = new FileSystemEntry(FileUtil.safeCreate(FileUtil.getUserLocation()));

        fileTableModel.setRoot(initialEntry);
        table.setModel(fileTableModel);
        
        table.getColumnModel().setColumnSelectionAllowed(false);
        table.getColumnModel().getColumn(0).setPreferredWidth(20);
        table.getColumnModel().getColumn(1).setPreferredWidth(220);
        table.getColumnModel().getColumn(2).setPreferredWidth(80);
        
        try {
            @SuppressWarnings("unchecked")
            DefaultRowSorter<EntryTableModel, String> sorter = ((DefaultRowSorter<EntryTableModel, String>)table.getRowSorter());
            sorter.setSortKeys(Arrays.asList(
                    new RowSorter.SortKey(0, SortOrder.ASCENDING),
                    new RowSorter.SortKey(1, SortOrder.ASCENDING)
            ));
            sorter.sort();
        }catch (Throwable e) {
        }
        
		JLabel lblFile = new JLabel("File:");
		JLabel lblMime = new JLabel("Mime:");
		JLabel lblDirectory = new JLabel("Directory?");
        
        ListSelectionListener listSelectionListener = new ListSelectionListener() {

            public void valueChanged(ListSelectionEvent event) {
                try {                    
                    Entry selectedEntry = getSelectedEntry();

                    /*
                     * Comparing with the current entry to avoid loading same resource multiple times.
                     * Event listener is called several times sometimes. Better (and correct) solution?
                     */
                    if ((null != selectedEntry) && (currentEntry != selectedEntry)) {
                        currentEntry = selectedEntry;
                        lblFile.setText("File: " + selectedEntry.getName());
                        lblDirectory.setText((selectedEntry.isDirectory() ? "Directory" : "File"));
                        if (selectedEntry.isDirectory()) {
                        	lblMime.setText("Mime: N/A");
                        }else {
                        	lblMime.setText("Mime: " + MimeType.fromFile(FileUtil.safeCreate(selectedEntry.getFullPath())).getType());
                        }
                        previewEntry(selectedEntry);
                    }
                } catch (Exception e) {
                  // handleException(Localization.ERROR_CANNOT_SELECT_ENTRY, e);
                }
            }
        };
        
        table.getSelectionModel().addListSelectionListener(listSelectionListener);
        
        table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "Enter");
        table.getActionMap().put("Enter", new AbstractAction() {
            
            public void actionPerformed(ActionEvent event) {
            Entry selectedEntry = getSelectedEntry();
                
            if (null != selectedEntry) {
               navigateToEntry(getSelectedEntry());
            }
            }
        });
        table.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                if (e.getClickCount() == 2) {
                    Entry selectedEntry = getSelectedEntry();
                    
                    if (null != selectedEntry) {      
                        if (selectedEntry.isDirectory()) {
                        	navigateToEntry(getSelectedEntry());
                        }else {
                        	try {
								Desktop.getDesktop().open(FileUtil.safeCreate(getSelectedEntry().getFullPath()));
							} catch (IOException e1) {
								e1.printStackTrace();
							}
                        }      
                    }

                }
            }
        });   
        
		scrollPane.setViewportView(table);
		
		JPanel panel = new JPanel();
		scrollPane.setRowHeaderView(panel);
		panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
		
		panel.add(lblFile);
		panel.add(lblDirectory);
		panel.add(lblMime);

	}
	
    private Entry getSelectedEntry() {
        int selectedIndex = table.getSelectionModel().getLeadSelectionIndex();
        int rowCount = table.getModel().getRowCount();
        
        if (selectedIndex >= 0 && selectedIndex < rowCount) {
            int modelRowIndex = table.convertRowIndexToModel(selectedIndex);

            return ((EntryTableModel)table.getModel()).getEntry(modelRowIndex);
        }
        return null;
    }

    private void navigateToEntry(Entry entry) {
        Entry navigationTarget = entry.navigationTarget();
        
        if (entry.isNavigationPossible() && (null != navigationTarget)) {
            table.getSelectionModel().clearSelection();
            ((EntryTableModel) table.getModel()).setRoot(navigationTarget);
            //view.getFrame().setTitle(navigationTarget.getFullPath());
        }
        //view.clearStatus();
    }
    
    private void previewEntry(Entry entry) {
        Preview preview = previewFactory.createPreview(new ExceptionHandler() {
			
			@Override
			public void handleException(String message, Exception exception) {
				exception.printStackTrace();
			}
		}, view, entry);
        preview.show();
        view.getPreviewContainer().repaint();
        view.clearStatus();
    }
    
    public class SetRootAction extends AbstractAction {

        private final ExceptionHandler exceptionHandler;
        
        public SetRootAction(ExceptionHandler exceptionHandler) {
            super(Localization.SETROOT_MENUITEM_LABEL);
            this.exceptionHandler = exceptionHandler;
            putValue(MNEMONIC_KEY, new Integer(KeyEvent.VK_O));
        }
        
        public void actionPerformed(ActionEvent e) {
            final String pathToBrowse = JOptionPane.showInputDialog(view.getFrame(),
                    Localization.BROWSE_DIALOG_MESSAGE, Localization.BROWSE_DIALOG_TITLE, JOptionPane.PLAIN_MESSAGE);

            //Creating entry in a separate thread as it can fail and be slow
            SwingWorker<Entry, Object> entryCreator = new SwingWorker<Entry, Object>() {

                @Override
                public Entry doInBackground() throws FileBrowserException {
                    return EntryFactory.create(pathToBrowse);
                }

                @Override
                protected void done() {
                    Entry selectedEntry = null;
                    try {
                        selectedEntry = get();
                    } catch (InterruptedException e) {
                        exceptionHandler.handleException(e.getCause().getMessage(), e);
                    } catch (ExecutionException e) {
                        exceptionHandler.handleException(e.getCause().getMessage(), e);
                    } catch (Exception e) {
                        exceptionHandler.handleException(e.getCause().getMessage(), e);                    
                    }

                    if ((null == selectedEntry) || !selectedEntry.isDirectory()) {
                        JOptionPane.showMessageDialog(view.getFrame(),
                                Localization.NO_ROOT_DIALOG_MESSAGE, Localization.NO_ROOT_DIALOG_TITLE,
                                JOptionPane.ERROR_MESSAGE);
                    }
                    if (null != selectedEntry) {
                        navigateToEntry(selectedEntry);
                    }
                }
            };
            entryCreator.execute();
        }
    }

}
